package top.jiangqiang.qianyi.common.filter.logging;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.core.text.StrUtil;
import top.jiangqiang.qianyi.common.filter.AbstractPathMatchingOrderedFilter;
import top.jiangqiang.qianyi.common.filter.caching.wrapper.CachingHttpServletRequestWrapper;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.List;

@Setter
@Getter
@Slf4j
public class RequestLoggingFilter extends AbstractPathMatchingOrderedFilter {

    /**
     * 是否打印请求体，请求体长度小于maxCacheLimit时才支持打印，避免占用过多内存
     */
    private boolean logRequestBody;
    /**
     * 是否打印header
     */
    private boolean logRequestHeaders;
    /**
     * 如果该请求体支持打印，但是超过此长度，则只截取部分进行打印
     */
    private int maxPrintBodyLength;

    public RequestLoggingFilter(List<String> includePatterns, int order, List<String> excludePatterns) {
        super(includePatterns, order, excludePatterns);
    }

    @Override
    protected void doEnhancedFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 生成请求ID
        String requestId = IdUtil.randomUUID();
        logRequest(request, requestId);
        try {
            chain.doFilter(request, response);
        } finally {
            logResponse(request, response, requestId);
        }
    }

    private void logRequest(HttpServletRequest request, String requestId) {
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("Request ID: ")
                .append(requestId)
                .append(" - ")
                .append(request.getMethod())
                .append(" ")
                .append(request.getRequestURL());

        String queryString = request.getQueryString();
        if (queryString != null && !queryString.isEmpty()) {
            queryString = URLDecoder.decode(queryString, StandardCharsets.UTF_8);
            logMessage.append("?").append(queryString);
        }

        if (logRequestHeaders) {
            logMessage.append("\nRequest Headers:");
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                logMessage.append("\n").append(headerName).append(": ").append(request.getHeader(headerName));
            }
        }
        if (logRequestBody) {
            if (request instanceof CachingHttpServletRequestWrapper requestWrapper && requestWrapper.isCached()) {
                logMessage.append("\nRequest Body: ");
                String body = requestWrapper.getContentAsString();
                int length = StrUtil.length(body);
                if (length > 0) {
                    if (length <= maxPrintBodyLength) {
                        logMessage.append(body);
                    } else {
                        logMessage.append(StrUtil.subByLength(body, 0, maxPrintBodyLength))
                                .append("......请求体过长（")
                                .append(length)
                                .append("），此处省略......");
                    }
                } else {
                    logMessage.append("\nRequest Body: ").append("没有请求体");
                }
            } else {
                logMessage.append("\n请求体未被缓存，无法打印");
            }
        }
        log.info(logMessage.toString());
    }

    private void logResponse(HttpServletRequest request, HttpServletResponse response, String requestId) {
        String logMessage = "Request ID: " +
                requestId +
                " - Response for " +
                request.getMethod() +
                " " +
                request.getRequestURL() +
                " - Status: " +
                response.getStatus();
        log.info(logMessage);
    }
}